package com.k2data.k2app.service;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.k2data.app.kmx.KmxClient;
import com.k2data.app.kmx.cond.DataRowsV4Builder;
import com.k2data.app.kmx.cond.KmxCond;
import com.k2data.app.kmx.domain.DataRows;
import com.k2data.k2app.common.*;
import com.k2data.k2app.constant.Constant;
import com.k2data.k2app.domain.BomDTO;
import com.k2data.k2app.domain.DeviceCond;
import com.k2data.k2app.domain.DeviceDTO;
import com.k2data.k2app.domain.MonitorDTO;
import com.k2data.k2app.domain.po.*;
import com.k2data.k2app.exception.K2ResponseException;
import com.k2data.k2app.mapper.*;
import com.k2data.k2app.rest.InstanceClient;
import com.k2data.k2app.utils.StringUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;

/**
 * @author lidong9144@163.com 17-6-26.
 */
@Service
@Log4j2
public class MonitorService {

    private final InstanceClient instanceClient;

    private final MonitorPointMapper monitorPointMapper;
    private final DeviceBomMapper deviceBomMapper;
    private final MonitorVariableMapper monitorVariableMapper;
    private final MonitorLimitValueMapper monitorLimitValueMapper;
    private final RDeviceMonitorPointMapper rDeviceMonitorPointMapper;
    private final KmxParams kmxParams;
    private final TMonitorPointMapper tMonitorPointMapper;
    private final MyConstant myConstant;
    private final DeviceMapper deviceMapper;
    @Autowired
    private TMonitorVariableMapper tMonitorVariableMapper;
    @Autowired
    private TMonitorLimitValueMapper tMonitorLimitValueMapper;
    @Autowired
    private RDeviceMonitorPointCopyMapper rDeviceMonitorPointCopyMapper;
    @Autowired
    private  CustomerMapper customerMapper;
    @Autowired
    private KmxRuleService kmxRuleService;
    @Autowired
    private DeviceService deviceService;

    @Autowired
    public MonitorService(MonitorPointMapper monitorPointMapper, DeviceBomMapper deviceBomMapper,
                          InstanceClient instanceClient, MonitorVariableMapper monitorVariableMapper,
                          MonitorLimitValueMapper monitorLimitValueMapper, RDeviceMonitorPointMapper rDeviceMonitorPointMapper,
                          KmxParams kmxParams, TMonitorPointMapper tMonitorPointMapper,
                          MyConstant myConstant, DeviceMapper deviceMapper) {
        this.monitorPointMapper = monitorPointMapper;
        this.deviceBomMapper = deviceBomMapper;
        this.instanceClient = instanceClient;
        this.monitorVariableMapper = monitorVariableMapper;
        this.monitorLimitValueMapper = monitorLimitValueMapper;
        this.rDeviceMonitorPointMapper = rDeviceMonitorPointMapper;
        this.kmxParams = kmxParams;
        this.tMonitorPointMapper = tMonitorPointMapper;
        this.myConstant = myConstant;
        this.deviceMapper = deviceMapper;
    }

    @Transactional
    public Long insertPoint(MonitorPoint monitorPoint) throws K2ResponseException {
        monitorPointMapper.insertSelective(monitorPoint);

        K2Assert.existDeviceId(monitorPoint.getDeviceId());

        RDeviceMonitorPoint r = new RDeviceMonitorPoint();
        r.setDeviceId(monitorPoint.getDeviceId());
        r.setMonitorPointId(monitorPoint.getId());
        rDeviceMonitorPointMapper.insertSelective(r);

        return monitorPoint.getId();
    }

    @Transactional
    public Long updatePoint(MonitorPoint monitorPoint) {
        monitorPointMapper.updateByPrimaryKeySelective(monitorPoint);
        return monitorPoint.getId();
    }

    @Transactional
    public Long deletePoint(Long id) {
        monitorPointMapper.deleteByPrimaryKey(id);
        return id;
    }

    @Transactional
    public Long insertVariable(MonitorVariable monitorVariable) {
        monitorVariableMapper.insertSelective(monitorVariable);
        return monitorVariable.getId();
    }

    @Transactional
    public Long updateVariable(MonitorVariable monitorVariable) {
        monitorVariableMapper.updateByPrimaryKeySelective(monitorVariable);
        return monitorVariable.getId();
    }

    @Transactional
    public Long deleteVariable(Long id) {
        monitorVariableMapper.deleteByPrimaryKey(id);
        return id;
    }

    @Transactional
    public Long insertLimit(MonitorLimitValue po) throws K2ResponseException {
        // 前端对应：  lt 低保  glt低低报  gt 高报 ggt 高高报

//        gt：大于，对应value必须是数值型字符串（如“123”，“-12.34”等），支持小数和负数；
//        lt：小于，value要求同gt；
//        eq：等于，value要求同gt；
//        ge：大于等于，value要求同gt；
//        le：小于等于，value要求同gt；
//        ne：等于，value要求同gt；
//        in：属于，value格式为 "{aaa, 123, -12.34}"，表示 fieldValue.toString()等于"aaa"(区分大小写) or “123” or “-12.34”；
//        range：区间，value格式为 "(0, 100]" 或 “(0, 20) (40, 60)” 或 "(,100) (200,)"，支持开闭区间、多区间、正负无穷区间。

        boolean flag = !"lt".equals(po.getRule())
                && !"glt".equals(po.getRule())
                && !"gt".equals(po.getRule())
                && !"ggt".equals(po.getRule());
        if (flag) {
            throw new K2ResponseException(400000, "Rule must be one of (lt, glt, gt, ggt)");
        }
        String rule = po.getRule();
        switch (rule) {
            case "lt":
                po.setLevel(1);
                break;
            case "glt":
                po.setLevel(2);
                break;
            case "gt":
                po.setLevel(1);
                break;
            case "ggt":
                po.setLevel(2);
                break;
            default:
                break;
        }
        monitorLimitValueMapper.insertSelective(po);
        return po.getId();
    }

    @Transactional
    public Long updateLimit(MonitorLimitValue monitorLimitValue) {
        log.debug("updateLimit");
        monitorLimitValueMapper.updateByPrimaryKeySelective(monitorLimitValue);
        return monitorLimitValue.getId();
    }


    @Transactional
    public Long updateLimitAndLimit2Kmx(MonitorLimitValue monitorLimitValue) {
        log.debug("updateLimitAndSyn");
        monitorLimitValueMapper.updateByPrimaryKeySelective(monitorLimitValue);
        DeviceCond deviceCond = new DeviceCond();
        deviceCond.setId(monitorLimitValue.getId());
        MonitorLimitValue monitorLimitValue1 = monitorLimitValueMapper.selectLimitValue(deviceCond).get(0);
        kmxRuleService.pushLimitOne(monitorLimitValue1);
        return monitorLimitValue.getId();
    }

    @Transactional
    public Long deleteLimit(Long id) {
        monitorLimitValueMapper.deleteByPrimaryKey(id);
        return id;
    }
    @Transactional
    public Long deleteLimitFlag(Long id) {
        MonitorLimitValue monitorLimitValue = monitorLimitValueMapper.selectByPrimaryKey(id);
        monitorLimitValue.setDeleteFlag(1);
        monitorLimitValueMapper.updateByPrimaryKeySelective(monitorLimitValue);
        return id;
    }

    public Long deleteLimitFlagByMonitorPoint(Long monitorPointId) {
        DeviceCond deviceCond = new DeviceCond();
        deviceCond.setMonitorPointId(monitorPointId);
        List<MonitorLimitValue> monitorLimitValue = monitorLimitValueMapper.selectLimitValueByTVarible(deviceCond);
        for (MonitorLimitValue limitValue : monitorLimitValue) {
            limitValue.setDeleteFlag(1);
            monitorLimitValueMapper.updateByPrimaryKeySelective(limitValue);
        }
        return 1L;
    }

    @Transactional
    public Long insertDevicePoint(RDeviceMonitorPoint point) {

        if(point.getChannelName()!=null && !"".equals(point.getChannelName())){
            point.setName(point.getChannelName());
        }
        point.setChannelName(null);
        rDeviceMonitorPointMapper.insertSelective(point);

        return point.getId();
    }

    @Transactional
    public Long insertDevicePointCopy(RDeviceMonitorPoint point) throws K2ResponseException {
        RDeviceMonitorPointCopy rDeviceMonitorPointCopy = OrikaMapperFactory.getMapper().map(point, RDeviceMonitorPointCopy.class);
        // 唯一性验证，验证字段（设备，部件，测点，通道）
        int countExist = rDeviceMonitorPointCopyMapper.isExist(rDeviceMonitorPointCopy);
        if(countExist>0){
            throw new K2ResponseException(ResponseConstant.OBJECT_HAS_EXIST,
                    String.format("%s", ResponseConstant.MSG_OBJECT_HAS_EXIST));
        }
        // 1 从 template_monitor_point 查询测点记录，插入 monitor_point中，关联 template_monitor_point 的 id ,返回 插入后的主键id
        TMonitorPoint tMonitorPoint = tMonitorPointMapper.selectByPrimaryKey(point.getMonitorPointId());
        MonitorPoint monitorPoint = OrikaMapperFactory.getMapper().map(tMonitorPoint, MonitorPoint.class);
        monitorPoint.setTMonitorPointId(point.getMonitorPointId());
        monitorPoint.setId(null);
        monitorPointMapper.insertBackId(monitorPoint);
        // 2 查询 template_monitor_varible 中的记录，插入 monitro_varible 中，关联１中的id
        List<TMonitorVariable> tMonitorVariables = tMonitorVariableMapper.selectByMPId(point.getMonitorPointId());
        for(TMonitorVariable tMonitorVariable:tMonitorVariables){
            MonitorVariable monitorVariable = OrikaMapperFactory.getMapper().map(tMonitorVariable, MonitorVariable.class);
            monitorVariable.setMonitorPointId(monitorPoint.getId());
            monitorVariable.setId(null);
            monitorVariableMapper.insertBackId(monitorVariable);
//            monitorVariables.add(monitorVariable);
            // 3 根据 template_monitor_varible 查询 template_monitor_limit_value　表，插入monitor_limit_value中，关联２中id
            TMonitorLimitValue tMonitorVariable1 = new TMonitorLimitValue();
            tMonitorVariable1.setVariableId(tMonitorVariable.getId());

            // 同步震动量的通频值规则，或者过程量的value规则
            if((monitorPoint.getTMonitorPointId() == 1 && "direc".equals(tMonitorVariable.getVariableNameEn())) ||
                    (monitorPoint.getTMonitorPointId() == 2 && "value".equals(tMonitorVariable.getVariableNameEn()))){
                if(point.getGtLimit()!=null){
                    //
                    MonitorLimitValue monitorLimitValue1 = new MonitorLimitValue();
                    monitorLimitValue1.setVariableId(monitorVariable.getId());
                    monitorLimitValue1.setName("高报");
                    monitorLimitValue1.setLevel(1);
                    monitorLimitValue1.setRule("lt");
                    monitorLimitValue1.setValue(point.getGtLimit());
                    monitorLimitValueMapper.insertSelective(monitorLimitValue1);
                }
                if(point.getGgtLimit()!=null){
                    MonitorLimitValue monitorLimitValue4 = new MonitorLimitValue();
                    monitorLimitValue4.setVariableId(monitorVariable.getId());
                    monitorLimitValue4.setName("高高报");
                    monitorLimitValue4.setLevel(2);
                    monitorLimitValue4.setRule("glt");
                    monitorLimitValue4.setValue(point.getGgtLimit());
                    monitorLimitValueMapper.insertSelective(monitorLimitValue4);
                }
                if(point.getLtLimit()!=null){
                    MonitorLimitValue monitorLimitValue2 = new MonitorLimitValue();
                    monitorLimitValue2.setVariableId(monitorVariable.getId());
                    monitorLimitValue2.setName("低报");
                    monitorLimitValue2.setLevel(1);
                    monitorLimitValue2.setRule("gt");
                    monitorLimitValue2.setValue(point.getLtLimit());
                    monitorLimitValueMapper.insertSelective(monitorLimitValue2);
                }
                if(point.getGltLimit()!=null){
                    MonitorLimitValue monitorLimitValue3 = new MonitorLimitValue();
                    monitorLimitValue3.setVariableId(monitorVariable.getId());
                    monitorLimitValue3.setName("低低报");
                    monitorLimitValue3.setLevel(2);
                    monitorLimitValue3.setRule("ggt");
                    monitorLimitValue3.setValue(point.getGltLimit());
                    monitorLimitValueMapper.insertSelective(monitorLimitValue3);
                }
            } else {
                List<TMonitorLimitValue> tMonitorLimitValues = tMonitorLimitValueMapper.select(tMonitorVariable1);
                for(TMonitorLimitValue tMonitorLimitValue:tMonitorLimitValues){
                    MonitorLimitValue monitorLimitValue = OrikaMapperFactory.getMapper().map(tMonitorLimitValue, MonitorLimitValue.class);
                    monitorLimitValue.setVariableId(monitorVariable.getId());
                    monitorLimitValue.setId(null);
                    monitorLimitValueMapper.insert(monitorLimitValue);
                }
            }
        }

        // 4 插入r_device_monotor_point 关联记录
        if(point.getChannelName()!=null && !"".equals(point.getChannelName())){
            rDeviceMonitorPointCopy.setName(point.getChannelName());
        }
        rDeviceMonitorPointCopy.setMonitorPointId(monitorPoint.getId());
        rDeviceMonitorPointCopyMapper.insertSelective(rDeviceMonitorPointCopy);
        return point.getId();
    }

    @Transactional
    public Long insertDevicePointCopySame(RDeviceMonitorPointCopy rDeviceMonitorPointCopy) throws K2ResponseException {
        // 唯一性验证，验证字段（设备，部件，测点，通道）
        int countExist = rDeviceMonitorPointCopyMapper.isExist(rDeviceMonitorPointCopy);
        if(countExist>0){
            throw new K2ResponseException(ResponseConstant.OBJECT_HAS_EXIST,
                    String.format("%s", ResponseConstant.MSG_OBJECT_HAS_EXIST));
        }
        // 1 从 template_monitor_point 查询测点记录，插入 monitor_point中，关联 template_monitor_point 的 id ,返回 插入后的主键id
        TMonitorPoint tMonitorPoint = tMonitorPointMapper.selectByPrimaryKey(rDeviceMonitorPointCopy.getMonitorPointId());
        MonitorPoint monitorPoint = OrikaMapperFactory.getMapper().map(tMonitorPoint, MonitorPoint.class);
        monitorPoint.setTMonitorPointId(rDeviceMonitorPointCopy.getMonitorPointId());
        monitorPoint.setId(null);
        monitorPointMapper.insertBackId(monitorPoint);
        // 2 查询 template_monitor_varible 中的记录，插入 monitro_varible 中，关联１中的id
        List<TMonitorVariable> tMonitorVariables = tMonitorVariableMapper.selectByMPId(rDeviceMonitorPointCopy.getMonitorPointId());
//        List<MonitorVariable> monitorVariables = Lists.newArrayList();
        for(TMonitorVariable tMonitorVariable:tMonitorVariables){
            MonitorVariable monitorVariable = OrikaMapperFactory.getMapper().map(tMonitorVariable, MonitorVariable.class);
            monitorVariable.setMonitorPointId(monitorPoint.getId());
            monitorVariable.setId(null);
            monitorVariableMapper.insertBackId(monitorVariable);
//            monitorVariables.add(monitorVariable);
            // 3 根据 template_monitor_varible 查询 template_monitor_limit_value　表，插入monitor_limit_value中，关联２中id
            TMonitorLimitValue tMonitorVariable1 = new TMonitorLimitValue();
            tMonitorVariable1.setVariableId(tMonitorVariable.getId());

            // 同步震动量的通频值规则，或者过程量的value规则
            if((monitorPoint.getTMonitorPointId() == 1 && "direc".equals(tMonitorVariable.getVariableNameEn())) ||
                    (monitorPoint.getTMonitorPointId() == 2 && "value".equals(tMonitorVariable.getVariableNameEn()))){
                if(rDeviceMonitorPointCopy.getGtLimit()!=null){
                    MonitorLimitValue monitorLimitValue1 = new MonitorLimitValue();
                    monitorLimitValue1.setVariableId(monitorVariable.getId());
                    monitorLimitValue1.setName("高报");
                    monitorLimitValue1.setLevel(1);
                    monitorLimitValue1.setRule("lt");
                    monitorLimitValue1.setValue(rDeviceMonitorPointCopy.getGtLimit());
                    monitorLimitValueMapper.insertSelective(monitorLimitValue1);
                }
                if(rDeviceMonitorPointCopy.getGgtLimit()!=null){
                    MonitorLimitValue monitorLimitValue4 = new MonitorLimitValue();
                    monitorLimitValue4.setVariableId(monitorVariable.getId());
                    monitorLimitValue4.setName("高高报");
                    monitorLimitValue4.setLevel(2);
                    monitorLimitValue4.setRule("lt");
                    monitorLimitValue4.setValue(rDeviceMonitorPointCopy.getGgtLimit());
                    monitorLimitValueMapper.insertSelective(monitorLimitValue4);
                }
                if(rDeviceMonitorPointCopy.getLtLimit()!=null){
                    MonitorLimitValue monitorLimitValue2 = new MonitorLimitValue();
                    monitorLimitValue2.setVariableId(monitorVariable.getId());
                    monitorLimitValue2.setName("低报");
                    monitorLimitValue2.setLevel(1);
                    monitorLimitValue2.setRule("ge");
                    monitorLimitValue2.setValue(rDeviceMonitorPointCopy.getLtLimit());
                    monitorLimitValueMapper.insertSelective(monitorLimitValue2);
                }
                if(rDeviceMonitorPointCopy.getGltLimit()!=null){
                    MonitorLimitValue monitorLimitValue3 = new MonitorLimitValue();
                    monitorLimitValue3.setVariableId(monitorVariable.getId());
                    monitorLimitValue3.setName("低低报");
                    monitorLimitValue3.setLevel(2);
                    monitorLimitValue3.setRule("ge");
                    monitorLimitValue3.setValue(rDeviceMonitorPointCopy.getGltLimit());
                    monitorLimitValueMapper.insertSelective(monitorLimitValue3);
                }
            } else {
                List<TMonitorLimitValue> tMonitorLimitValues = tMonitorLimitValueMapper.select(tMonitorVariable1);
                for(TMonitorLimitValue tMonitorLimitValue:tMonitorLimitValues){
                    MonitorLimitValue monitorLimitValue = OrikaMapperFactory.getMapper().map(tMonitorLimitValue, MonitorLimitValue.class);
                    monitorLimitValue.setVariableId(monitorVariable.getId());
                    monitorLimitValue.setId(null);
                    monitorLimitValueMapper.insert(monitorLimitValue);
                }
            }
        }

        // 4 插入r_device_monotor_point 关联记录
        if(rDeviceMonitorPointCopy.getChannelName()!=null && !"".equals(rDeviceMonitorPointCopy.getChannelName())){
            rDeviceMonitorPointCopy.setName(rDeviceMonitorPointCopy.getChannelName());
        }
        rDeviceMonitorPointCopy.setMonitorPointId(monitorPoint.getId());
        rDeviceMonitorPointCopyMapper.insertSelective(rDeviceMonitorPointCopy);
        return rDeviceMonitorPointCopy.getId();
    }

    /**
     * 将模板测点表的记录同步到设备测点表中
     * <p>不包含重复记录
     *
     * @return
     */
    @Transactional
    public Long synTemplatePoint(String type){
        List<RDeviceMonitorPoint> rDeviceMonitorPoints = Lists.newArrayList();
        if(type!=null && type.equals("first")){
            rDeviceMonitorPoints = rDeviceMonitorPointMapper.selectAll();
        }else{
            rDeviceMonitorPoints = rDeviceMonitorPointMapper.selectNotSynLimit();
        }
        for(int i=0;i<rDeviceMonitorPoints.size();i++){
            try {
                RDeviceMonitorPoint rDeviceMonitorPoint = rDeviceMonitorPoints.get(i);
                rDeviceMonitorPoint.setId(null);
                insertDevicePointCopy(rDeviceMonitorPoint);
            } catch (K2ResponseException e) {
                e.printStackTrace();
            }
        }
        return 1L;
    }

    /**
     * 将重复记录的id最大一条同步到设备测点表中
     * @return
     */
    @Transactional
    public Long synTemplatePointSame(){
        List<RDeviceMonitorPointCopy> rDeviceMonitorPoints = rDeviceMonitorPointCopyMapper.selectSameOne();
        for(int i=0;i<rDeviceMonitorPoints.size();i++){
            try {
                RDeviceMonitorPointCopy rDeviceMonitorPoint = rDeviceMonitorPoints.get(i);
                rDeviceMonitorPoint.setId(null);
                insertDevicePointCopySame(rDeviceMonitorPoint);
            } catch (K2ResponseException e) {
                e.printStackTrace();
            }
        }
        return 1L;
    }

    @Transactional
    public Long updateDevicePoint(RDeviceMonitorPoint point) {
        rDeviceMonitorPointMapper.updateByPrimaryKeySelective(point);
        return point.getId();
    }
    @Transactional
    public Long deleteDevicePoint(Long rid) {
        rDeviceMonitorPointMapper.deleteByPrimaryKey(rid);
        return rid;
    }

    @Transactional
    public Long updateDevicePointCopy(RDeviceMonitorPointCopy point) throws K2ResponseException{

        RDeviceMonitorPointCopy rDeviceMonitorPointCopy = rDeviceMonitorPointCopyMapper.selectByPrimaryKey(point.getId());
        if(point.getChannelName()!=null&& !"".equals(point.getChannelName())){
            rDeviceMonitorPointCopy.setName(point.getChannelName());
        }
        rDeviceMonitorPointCopy.setChannelName(null);
        rDeviceMonitorPointCopy.setMonitorPointId(null);
        rDeviceMonitorPointCopyMapper.updateByPrimaryKeySelective(rDeviceMonitorPointCopy);
        return point.getId();
    }


    public Long deleteDevicePointCopy(Long rid) {
        RDeviceMonitorPointCopy rDeviceMonitorPointCopy = rDeviceMonitorPointCopyMapper.selectByPrimaryKey(rid);
        // 删除规则表  (delete_flag设为1，删除标志)
        deleteLimitFlagByMonitorPoint(rDeviceMonitorPointCopy.getMonitorPointId());
        // 同步规则表  (同步kmx中的规则)
        kmxRuleService.pushLimitCopy(rid);
        // 删除测点变量(monitor_variable)
        MonitorVariable monitorVariable = new MonitorVariable();
        monitorVariable.setMonitorPointId(rDeviceMonitorPointCopy.getMonitorPointId());
        monitorVariableMapper.delete(monitorVariable);
        // 删除测点(monitor_point)
        monitorPointMapper.deleteByPrimaryKey(rDeviceMonitorPointCopy.getMonitorPointId());
        // 删除关联关系(r_device_monitor_point_copy)
        rDeviceMonitorPointCopyMapper.deleteByPrimaryKey(rid);
        return rid;
    }

    public List<MonitorDTO> selectTDeviceVariables(DeviceCond cond) {
        List<MonitorDTO> list = Lists.newArrayList();

        for (MonitorVariable po : monitorVariableMapper.selectVariables(cond)) {
            MonitorDTO dto = OrikaMapperFactory.getMapper().map(po, MonitorDTO.class);

            list.add(dto);
        }

        return list;
    }

    public List<MonitorDTO> selectTDeviceLimit(DeviceCond cond) {
        List<MonitorDTO> list = Lists.newArrayList();
        for (MonitorLimitValue po : monitorLimitValueMapper.selectLimitValue(cond)) {
            MonitorDTO dto = new MonitorDTO();
            dto.setName(po.getName());
            dto.setValue(po.getValue());
            dto.setRule(po.getRule());
            dto.setId(po.getId());
            dto.setVariableId(po.getVariableId());
            dto.setState(po.getState());

            list.add(dto);
        }

        return list;
    }


    public List<MonitorLimitValue> selectLimitValueByTVarible(DeviceCond cond) {
        List<MonitorLimitValue> monitorLimitValues = monitorLimitValueMapper.selectLimitValueByTVarible(cond);
        return monitorLimitValues ;
    }


    public List<MonitorDTO> selectPoints(DeviceCond cond) {
        List<MonitorDTO> list = Lists.newArrayList();

        List<MonitorPoint> source = monitorPointMapper.selectPoints(cond);
        for (MonitorPoint po : source) {
            for (RDeviceMonitorPointCopy rDeviceMonitorPoint : po.getRs()) {
                MonitorDTO dto = OrikaMapperFactory.getMapper().map(po, MonitorDTO.class);
                dto.setRid(rDeviceMonitorPoint.getId());
                dto.setChannelId(rDeviceMonitorPoint.getChannelId());
                dto.setChannelName(rDeviceMonitorPoint.getName());
                dto.setDeviceName(rDeviceMonitorPoint.getDeviceName());
                dto.setGtLimit(rDeviceMonitorPoint.getGtLimit());
                dto.setGgtLimit(rDeviceMonitorPoint.getGgtLimit());
                dto.setLtLimit(rDeviceMonitorPoint.getLtLimit());
                dto.setGltLimit(rDeviceMonitorPoint.getGltLimit());
                dto.setState(rDeviceMonitorPoint.getState());
                list.add(dto);
            }
        }

        return list;
    }

    private void bomMonitorPoints( List<MonitorPoint> source,List<DeviceDTO> children,DeviceCond cond){
        if(children.size() > 0){
            children.forEach(s->{
                DeviceCond cond1 = OrikaMapperFactory.getMapper().map(cond, DeviceCond.class);
                cond1.setDeviceId(s.getId());
                List<MonitorPoint> devicePoints = monitorPointMapper.selectPointsCopy(cond1);
                source.addAll(devicePoints);
                bomMonitorPoints(source,s.getChildren(),cond);
            });
        }
    }

    public List<MonitorDTO> selectPointsCopy(DeviceCond cond) {
        List<MonitorDTO> list = Lists.newArrayList();
        List<MonitorPoint> source = Lists.newArrayList();

        List<MonitorPoint> source1 = monitorPointMapper.selectPointsCopy(cond);
        source.addAll(source1);
        if(cond.getDeviceId() != null){
            DeviceDTO self = new DeviceDTO();
            self.setChildren(Lists.newArrayList());
            deviceService.bom(cond.getRootId(),cond.getDeviceId(),self.getChildren());
            bomMonitorPoints(source,self.getChildren(),cond);
        }

        for (MonitorPoint po : source) {
            String defaultVarible ;
            switch (String.valueOf(po.getTMonitorPointId())){
                case "1":
                    defaultVarible="direc";
                    break;
                case "2":
                    defaultVarible="value";
                    break;
                default:
                    defaultVarible="direc";
                    break;

            }
            for (RDeviceMonitorPointCopy rDeviceMonitorPoint : po.getRs()) {
                MonitorDTO dto = OrikaMapperFactory.getMapper().map(po, MonitorDTO.class);
                dto.setRid(rDeviceMonitorPoint.getId());
                dto.setChannelId(rDeviceMonitorPoint.getChannelId());
                dto.setChannelName(rDeviceMonitorPoint.getName());
                dto.setName(rDeviceMonitorPoint.getName());
                dto.setDeviceName(rDeviceMonitorPoint.getDeviceName());
                dto.setDeviceId(rDeviceMonitorPoint.getDeviceId());
                DeviceCond deviceCond1 = new DeviceCond();
                deviceCond1.setDeviceId(cond.getRootId());
                deviceCond1.setMonitorPointId(po.getId());
                deviceCond1.setDefaultVariable(defaultVarible);
                List<MonitorLimitValue> monitorLimitValues = monitorLimitValueMapper.selectLimitValue(deviceCond1);
                monitorLimitValues.forEach(s->{
                    switch (s.getRule()){
                        case "lt":
                            dto.setLtLimit(s.getValue());
                            break;
                        case "gt":
                            dto.setGtLimit(s.getValue());
                            break;
                        case "glt":
                            dto.setGltLimit(s.getValue());
                            break;
                        case "ggt":
                            dto.setGgtLimit(s.getValue());
                            break;
                    }
                });
                dto.setState(rDeviceMonitorPoint.getState());
                list.add(dto);
            }
        }

        for (MonitorDTO monitorDTO:list) {
            if(monitorDTO.getSensorType().contains("tcs")){
                String[] arr =monitorDTO.getSensorType().split("_");
                String deviceNo=arr[1]+"_10000_"+arr[2];
                String customerNo=arr[0]+"_"+arr[1];
                Device device=deviceMapper.selectByDeviceNo(deviceNo);
                Customer customer=customerMapper.selectByCustomerNo(customerNo);
                monitorDTO.setSensorName(device.getName());//设置成设备名字
                monitorDTO.setSensorType(customer.getName());//设置成客户名称
            }
        }
        return list;
    }


    public List<MonitorDTO> selectDevicePoints(DeviceCond cond) {
        List<MonitorDTO> list = Lists.newArrayList();

        List<MonitorPoint> source = monitorPointMapper.selectPointsCopy(cond);
        for (MonitorPoint po : source) {
            if (cond.getDeviceId() != null || cond.getRootId() != null) {
                for (RDeviceMonitorPointCopy trDeviceMonitorPoint : po.getRs()) {
                    MonitorDTO dto = new MonitorDTO();
                    dto.setId(po.getId());
                    dto.setSensorName(po.getSensorName());
                    dto.setSensorType(po.getSensorType());
                    dto.setNameEn(po.getNameEn());
                    dto.setName(trDeviceMonitorPoint.getName());
                    dto.setDeviceName(trDeviceMonitorPoint.getDeviceName());
                    dto.setState(po.getState());
                    dto.setRid(trDeviceMonitorPoint.getId());
                    list.add(dto);
                }
            } else {
                if(po.getRs()!=null){
                    for (RDeviceMonitorPointCopy trDeviceMonitorPoint : po.getRs()) {
                        MonitorDTO dto = new MonitorDTO();
                        dto.setId(po.getId());
                        dto.setSensorName(po.getSensorName());
                        dto.setSensorType(po.getSensorType());
                        dto.setNameEn(po.getNameEn());
                        dto.setDeviceName(po.getDeviceName());
                        dto.setName(trDeviceMonitorPoint.getName());
                        dto.setState(po.getState());
                        list.add(dto);
                    }
                }
            }
        }

        for (MonitorDTO monitorDTO:list) {
            if(monitorDTO.getSensorType().contains("tcs")){
                String[] arr =monitorDTO.getSensorType().split("_");
                String deviceNo=arr[1]+"_10000_"+arr[2];
                String customerNo=arr[0]+"_"+arr[1];
                Device device=deviceMapper.selectByDeviceNo(deviceNo);
                Customer customer=customerMapper.selectByCustomerNo(customerNo);
                monitorDTO.setSensorName(device.getName());//设置成设备名字
                monitorDTO.setSensorType(customer.getName());//设置成客户名称
            }
        }
        return list;
    }

    public List<MonitorDTO> selectVariables(DeviceCond cond) {
        List<MonitorDTO> list = Lists.newArrayList();

        for (MonitorVariable po : monitorVariableMapper.selectVariables(cond)) {
            MonitorDTO dto = OrikaMapperFactory.getMapper().map(po, MonitorDTO.class);

            list.add(dto);
        }

        return list;
    }

    public List<MonitorDTO> selectLimits(DeviceCond cond) {
        List<MonitorDTO> list = Lists.newArrayList();
        for (MonitorLimitValue po : monitorLimitValueMapper.selectLimitValue(cond)) {
            MonitorDTO dto = OrikaMapperFactory.getMapper().map(po, MonitorDTO.class);
            list.add(dto);
        }

        return list;
    }

    public List<MonitorDTO> selectAllVariables(DeviceCond cond) throws InterruptedException {
        List<MonitorDTO> list = Lists.newArrayList();

        List<TMonitorPoint> points = tMonitorPointMapper.selectDeviceVariable(cond);
        Device device = deviceMapper.selectByPrimaryKey(cond.getRootId());

        for (TMonitorPoint point : points) {
            // tcs 特殊处理
          /*  if (point.getNameEn().startsWith("tcs")) {
                String a = Joiner.on("_").join(Splitter.on('_')
                        .trimResults()
                        .omitEmptyStrings()
                        .splitToList(point.getNameEn()).subList(0, 2));


            }*/
            point.setNameEn(point.getNameEn());

            Map<String, Object[]> values = Maps.newHashMap();
            if (cond.getKmxValue() != null) {
                try {
                    values = getKmxValue(point, cond, device);
                } catch (Exception e) {
                    log.error("", e);
                }
            }

            for (TMonitorVariable var : point.getMonitorVariables()) {
                if("STRING".equalsIgnoreCase(var.getKmxVariableType())) {
                    continue;
                }

                MonitorDTO dto = OrikaMapperFactory.getMapper().map(var, MonitorDTO.class);
                dto.setSensorName(point.getSensorName());
                dto.setSensorType(point.getSensorType());
                dto.setSensorNameEn(point.getNameEn());
                list.add(dto);

                if (cond.getKmxValue() != null) {
                    Object[] value = values.get(var.getKmxVariableNameEn());

                    if (value == null || value.length != 2) {
                        dto.setKmxValue("-");
                        continue;
                    }

                    dto.setKmxValue(value[0].toString());
                    String level = value[1].toString();
                    dto.setLimitType(level);
                }
            }
        }

        return list;
    }

    public List<MonitorDTO> selectAllVariablesCopy(DeviceCond cond) throws InterruptedException {
        List<MonitorDTO> list = Lists.newArrayList();

        List<MonitorPoint> points = monitorPointMapper.selectDeviceVariable(cond);
        Device device = deviceMapper.selectByPrimaryKey(cond.getRootId());

        for (MonitorPoint point : points) {
            // tcs 特殊处理
            /*if (point.getNameEn().startsWith("tcs")) {
                String a = Joiner.on("_").join(Splitter.on('_')
                        .trimResults()
                        .omitEmptyStrings()
                        .splitToList(point.getNameEn()).subList(0, 2));
            }*/

            point.setNameEn(myConstant.getFieldGroup(point.getNameEn()));
            Map<String, Object[]> values = Maps.newHashMap();
            if (cond.getKmxValue() != null) {
                try {
                    values = getKmxValueCopy(point, cond, device);
                } catch (Exception e) {
                    log.error("", e);
                }
            }

            for (MonitorVariable var : point.getVariables()) {
                if("STRING".equalsIgnoreCase(var.getKmxVariableType())) {
                    continue;
                }

                MonitorDTO dto = OrikaMapperFactory.getMapper().map(var, MonitorDTO.class);
                dto.setSensorName(point.getSensorName());
                dto.setSensorType(point.getSensorType());
                dto.setSensorNameEn(point.getNameEn());
                dto.setChannelId(point.getChannelId());
                dto.setChannelName(point.getChannelName());
                list.add(dto);

                if (cond.getKmxValue() != null) {
                    Object[] value = values.get(var.getKmxVariableNameEn());

//                    if (value == null || value.length != 2) {
                    if (value == null) {
                        dto.setKmxValue("-");
                        continue;
                    }

                    dto.setKmxValue(value[0].toString());
                    if(Double.valueOf(dto.getKmxValue())<=-1000000){
                        dto.setKmxValue("-");
                    }
                    String level = value[1].toString();
                    dto.setLimitType(level);
                    Long timestamp = Long.valueOf(value[2].toString());
                    dto.setTimeStamp(timestamp);
                }
            }
        }
        return list;
    }

    private Map<String, Object[]> getKmxValue(TMonitorPoint point, DeviceCond cond, Device device) {
        Map<String, Object[]> fieldMap = Maps.newHashMap();

        Map<String, List<String>> fields = Maps.newHashMap();
        for (TMonitorVariable var : point.getMonitorVariables()) {
            fields.putIfAbsent(point.getNameEn(), Lists.newArrayList());
            fields.get(point.getNameEn()).add(var.getKmxVariableNameEn());
            fields.get(point.getNameEn()).add("$" + var.getKmxVariableNameEn() + "_state");
        }

        for (Map.Entry<String, List<String>> entry : fields.entrySet()) {
            List<String> ss = Splitter.on('_')
                    .trimResults()
                    .omitEmptyStrings()
                    .splitToList(device.getDeviceNo());

            DataRowsV4Builder dataRowsV4Builder = KmxCond.dataRows(kmxParams.getKmxInitParams())
                    .url(myConstant.getDataRowsRealTimeUrl())
                    .fieldGroup(entry.getKey())
                    .fields(entry.getValue())
                    .idValue(ss.get(2))
                    .idField(MyConstant.KMX_ID_FIELD_CHANNEL_ID, cond.getChannelId() == null ? "" : cond.getChannelId().toString())
                    .idField(MyConstant.KMX_ID_FIELD_FACTORY_NAME, ss.get(0))
                    .idField(MyConstant.KMX_ID_FIELD_EQUIPMENT_NAME, ss.get(1))
                    .idField(MyConstant.KMX_ID_FIELD_DATA_TYPE, "1")
                    .start("now-10m")
                    .end("now")
                    .desc()
                    .size(1)
                    .page(1);

            KmxCond kmxCond = dataRowsV4Builder.build();

            DataRows dataRows = KmxClient.sync(kmxCond);
            if (dataRows.getFirstResultRows().size() > 0
                    && dataRows.getFirstResultRows().get(0).getValues() != null
                    && dataRows.getFirstResultRows().get(0).getValues().size() > 0) {
                List<Object> values = dataRows.getFirstResultRows().get(0).getValues();

                for (int i = 0; i < entry.getValue().size(); i = i + 2) {
                    String field = entry.getValue().get(i);
                    Object o1 = values.get(i);
                    Object o2 = values.get(i + 1);
                    fieldMap.put(field, new Object[]{o1 == null ? 0 : o1, o2 == null ? "" : o2});
                }
            }
        }
        return fieldMap;
    }

    private Map<String, Object[]> getKmxValueCopy(MonitorPoint point, DeviceCond cond, Device device) {
        Map<String, Object[]> fieldMap = Maps.newHashMap();

        Map<String, List<String>> fields = Maps.newHashMap();
        for (MonitorVariable var : point.getVariables()) {
            fields.putIfAbsent(point.getNameEn(), Lists.newArrayList());
            fields.get(point.getNameEn()).add(var.getKmxVariableNameEn());
            fields.get(point.getNameEn()).add("$" + var.getKmxVariableNameEn() + "_state");
        }

        for (Map.Entry<String, List<String>> entry : fields.entrySet()) {
            List<String> ss = Splitter.on('_')
                    .trimResults()
                    .omitEmptyStrings()
                    .splitToList(device.getDeviceNo());

            DataRowsV4Builder dataRowsV4Builder = KmxCond.dataRows(kmxParams.getKmxInitParams())
                    .url(myConstant.getDataRowsRealTimeUrl())
                    .fieldGroup(entry.getKey())
                    .fields(entry.getValue())
                    .idValue(ss.get(2))
                    .idField(MyConstant.KMX_ID_FIELD_CHANNEL_ID, point.getChannelId() == null ? "" : point.getChannelId().toString())
                    .idField(MyConstant.KMX_ID_FIELD_FACTORY_NAME, ss.get(0))
                    .idField(MyConstant.KMX_ID_FIELD_EQUIPMENT_NAME, ss.get(1))
                    .idField(MyConstant.KMX_ID_FIELD_DATA_TYPE, "1")
                    .start("now-30m")
                    .end("now")
                    .desc()
                    .size(1)
                    .page(1);

            KmxCond kmxCond = dataRowsV4Builder.build();

            DataRows dataRows = KmxClient.sync(kmxCond);
            if (dataRows.getFirstResultRows().size() > 0
                    && dataRows.getFirstResultRows().get(0).getValues() != null
                    && dataRows.getFirstResultRows().get(0).getValues().size() > 0) {
                List<Object> values = dataRows.getFirstResultRows().get(0).getValues();
                Object timestamp = dataRows.getFirstResultRows().get(0).getTimestamp();
                for (int i = 0; i < entry.getValue().size(); i = i + 2) {
                    String field = entry.getValue().get(i);
                    Object o1 = values.get(i);
                    Object o2 = values.get(i + 1);
                    fieldMap.put(field, new Object[]{o1 == null ? 0 : o1, o2 == null ? "" : o2,timestamp});
                }
            }
        }
        return fieldMap;
    }

    /**
     * 遍历 bom 树, 广度优先
     * <p>把所有 bom 存入 list
     */
    public List<BomDTO> selectDeviceBomWide(Long tDeviceId) throws InterruptedException {
        LinkedBlockingQueue<Long> deviceIdQueue = new LinkedBlockingQueue<>();

        List<BomDTO> boms = Lists.newArrayList();

        DeviceBom condSelf = new DeviceBom();
        condSelf.setDeviceId(tDeviceId);
        DeviceBom self = deviceBomMapper.selectOneBom(condSelf);
        if (self != null) {
            BomDTO dto = new BomDTO();

            if (self.getDevice() != null) {
                dto = OrikaMapperFactory.getMapper().map(self.getDevice(), BomDTO.class);

                if (!StringUtils.isBlank(self.getDevice().getImageUrl())) {
                    dto.setImageUrl(instanceClient.getGatewayUrl() + Paths.get("/static/", self.getDevice().getImageUrl()).toString());
                } else {
                    dto.setImageUrl(instanceClient.getGatewayUrl() + "/static/template_default.png");
                }
            }

            dto.setBomId(self.getId());
            dto.setParentId(self.getParentId());

            boms.add(dto);
        }

        DeviceBom cond = new DeviceBom();
        cond.setParentId(tDeviceId);
        addWideItem(cond, deviceIdQueue, boms);

        while (!deviceIdQueue.isEmpty()) {
            DeviceBom innerCond = new DeviceBom();
            innerCond.setParentId(deviceIdQueue.take());

            addWideItem(innerCond, deviceIdQueue, boms);
        }

        return boms;
    }

    private void addWideItem(DeviceBom innerCond, LinkedBlockingQueue<Long> deviceIdQueue, List<BomDTO> boms) throws InterruptedException {
        List<DeviceBom> leafs = deviceBomMapper.selectBom(innerCond);

        for (DeviceBom leaf : leafs) {
            deviceIdQueue.put(leaf.getDeviceId());

            BomDTO dto = new BomDTO();
            if (leaf.getDevice() != null) {
                dto = OrikaMapperFactory.getMapper().map(leaf.getDevice(), BomDTO.class);

                if (Constant.YES.equals(leaf.getDevice().getIsRoot())) {
                    if (!StringUtils.isBlank(leaf.getDevice().getImageUrl())) {
                        dto.setImageUrl(instanceClient.getGatewayUrl() + Paths.get("/static/", leaf.getDevice().getImageUrl()).toString());
                    } else {
                        dto.setImageUrl(instanceClient.getGatewayUrl() + "/static/template_default.png");
                    }
                }
            }
            dto.setBomId(leaf.getId());
            dto.setParentId(leaf.getParentId());
            boms.add(dto);
        }
    }

}
